package com.tengju.bff.interfaces.app.withdraw.facade;

import com.beust.jcommander.internal.Lists;
import com.tengju.bff.interfaces.app.withdraw.assembler.DepositoryAssembler;
import com.tengju.bff.interfaces.app.withdraw.vo.*;
import com.tengju.bff.interfaces.shared.*;
import com.tengju.payment.application.shard.ApplicationException;
import com.tengju.payment.application.shard.ApplicationExceptionCode;
import com.tengju.settlement.application.depository.DepositoryService;
import com.tengju.settlement.domain.model.account.UserIdCode;
import com.tengju.settlement.domain.model.depository.*;
import com.tengju.settlement.domain.service.RemotePaymentService;
import com.tengju.settlement.domain.shared.Amount;
import com.tengju.settlement.domain.shared.JsonUtil;
import com.tengju.user.application.sign.SignService;
import com.tengju.user.application.user.UserInfoService;
import com.tengju.user.domain.model.archive.letax.IdentityType;
import com.tengju.user.domain.model.archive.sign.SelfCertification;
import com.tengju.user.domain.model.archive.sign.SignInfo;
import com.tengju.user.domain.model.user.UserInfo;
import com.tengju.user.domain.model.user.UserInfoRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class DepositoryFacade {

    private final DepositoryAccountRepository depositoryAccountRepository;
    private final DepositoryBankCardRepository depositoryBankCardRepository;
    private final SignService signService;
    private final RemotePaymentService paymentService;
    private final DepositoryService depositoryService;
    private final UserInfoRepository userInfoRepository;
    private final UserInfoService userInfoService;

    @Value("${abm.home.jump.url}")
    private String abmJumpUrl;

//    @Value("${abm.account.open.filter}")
//    private String abmOpenFilter;

    @Value("${abm.download.url}")
    private String abmDownloadUrl;

    @Value("${max.bind.card.count.ping.an.everyday:5}")
    private int maxBindCardCntForPingAnEveryday;

    @Value("${bind.card.count.redis.key.valid.hours:24}")
    private int bindCardCntValidHours;

    @Value("${super.bank.number.background.url.map.json.for.hot.bank:}")
    private String hotSuperBankNumberImgUrlMapJson;

    @Value("${depository.account.whiteList}")
    private String DepAccountWhiteList;


    public BindStatusVO bindStatus(UserIdCode idCode) {

//        if (!StringUtils.isEmpty(abmOpenFilter)) {
//            List<UserIdCode> filterIdCodeList = Arrays.stream(abmOpenFilter.split(","))
//                    .map(Long::parseLong)
//                    .map(UserIdCode::new)
//                    .collect(Collectors.toList());
//            if (filterIdCodeList.contains(idCode)) {i/withdrawal/apply
//                return new BindStatusVO(2, "", true, false, abmJumpUrl, abmDownloadUrl);
//            }
//        }

        boolean hitWhiteList = false;
        if (!StringUtils.isEmpty(DepAccountWhiteList)) {
            List<UserIdCode> whiteIdCodeList = Arrays.stream(DepAccountWhiteList.split(","))
                    .map(Long::parseLong)
                    .map(UserIdCode::new)
                    .collect(Collectors.toList());
            hitWhiteList = whiteIdCodeList.contains(idCode);
        }

        SignInfo signInfo = signService.getSignInfo(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));

        if (signInfo == null) {
            throw ApplicationException.error(ApplicationExceptionCode.SIGN_NOT_SUCCESS);
        }

        DepositoryBankCard successBankCard = null;
        DepositoryAccount depositoryAccount = null;
        Boolean abmOpened = true;
        boolean canImport = false;
        if (hitWhiteList) {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(idCode, DepositoryChannel.INTERNAL);
            if (depositoryAccount != null && AccountStatus.NORMAL == depositoryAccount.getStatus()) {
                List<DepositoryBankCard> depositoryBankCards = depositoryBankCardRepository
                        .getByDepositoryAccountIdStatus(idCode, depositoryAccount.getDepositoryAccountId(), List.of(BindStatus.SUCCESS));
                if (!CollectionUtils.isEmpty(depositoryBankCards)) {
                    successBankCard = depositoryBankCards.get(0);
                }
            }

        } else {
            //存管账户信息
            List<DepositoryAccount> depositoryAccounts = depositoryAccountRepository.getByIdCodeStatus(idCode,
                    List.of(AccountStatus.NORMAL, AccountStatus.CARD_BINDING), DepositoryChannel.PING_AN);
            //存管绑卡信息

            if (!CollectionUtils.isEmpty(depositoryAccounts)) {
                depositoryAccount = depositoryAccounts.get(0);
                if (depositoryAccount != null && AccountStatus.NORMAL == depositoryAccount.getStatus()) {
                    List<DepositoryBankCard> bankCards = depositoryBankCardRepository
                            .getByDepositoryAccountIdStatus(idCode,
                                    depositoryAccount.getDepositoryAccountId(), List.of(BindStatus.SUCCESS));
                    if (!CollectionUtils.isEmpty(bankCards)) {
                        successBankCard = bankCards.get(0);
                    }
                }
            }

            //绑卡信息为空,判断是否需要同步

            Integer openAccountNum = depositoryAccountRepository.countByIdCodeStatus(idCode,
                    List.of(AccountStatus.NORMAL, AccountStatus.LOGICAL_CANCEL, AccountStatus.CARD_NOT_BIND, AccountStatus.CARD_BINDING),
                    DepositoryChannel.PING_AN);
            if (openAccountNum == 0) {
                AbmDepositoryAggregatedInfo abmDepositoryInfo =
                        paymentService.getAbmAggregatedInfoForDepository(idCode, DepositoryChannel.PING_AN);
                //ABM未绑卡
                if (abmDepositoryInfo == null || !abmDepositoryInfo.isValid()) {
                    abmOpened = null;
                } else {

                    License license;
                    if (BankCardType.PUBLIC == abmDepositoryInfo.cardType()) {
                        license = convert(signInfo.companyDepAccountLicense());
                    } else {
                        license = convert(signInfo.personalDepAccountLicense());
                    }
                    //ABM已绑卡 && 证件一致  可以同步
                    if (abmDepositoryInfo.compareAccountLicense(license)) {
                        canImport = true;
                        //对公户需要校验法人人
                        if (abmDepositoryInfo.cardType() == BankCardType.PUBLIC &&
                                !abmDepositoryInfo.compareLegalAccountLicense(convert(signInfo.legalLicense()))) {
                            canImport = false;
                        }
                    }
                }
            }
        }

        return DepositoryAssembler.toBindStatusVO(depositoryAccount, successBankCard, abmOpened, canImport, abmJumpUrl, abmDownloadUrl, hitWhiteList);

    }

    public WhiteListBindCardVO whiteListCardInfo(UserIdCode idCode) {

        boolean hitWhiteList = false;
        if (!StringUtils.isEmpty(DepAccountWhiteList)) {
            List<UserIdCode> whiteIdCodeList = Arrays.stream(DepAccountWhiteList.split(","))
                    .map(Long::parseLong)
                    .map(UserIdCode::new)
                    .collect(Collectors.toList());
            hitWhiteList = whiteIdCodeList.contains(idCode);
        }

        if (!hitWhiteList) {
            throw ApplicationException.error(ApplicationExceptionCode.WHITE_LIST_NOT_HIT);
        }

        SignInfo signInfo = signService.getSignInfo(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));

        String accountName = signInfo.personalDepAccountName();
        com.tengju.user.domain.model.sign.License license = signInfo.personalDepAccountLicense();
        DepositoryAccount depositoryAccount = depositoryAccountRepository.getByIdCodeStatusNormal(idCode, DepositoryChannel.INTERNAL);
        List<DepositoryBankCard> depositoryBankCards = depositoryBankCardRepository
                .getByDepositoryAccountIdStatus(idCode, depositoryAccount.getDepositoryAccountId(), List.of(BindStatus.SUCCESS));

        if (CollectionUtils.isEmpty(depositoryBankCards)) {
            throw ApplicationException.error(ApplicationExceptionCode.DEP_BAND_CARD_NOT_BOUND);
        }
        String cardNo = depositoryBankCards.get(0).getCardNo();
        return new WhiteListBindCardVO(MaskCypherUtil.mask(license.getLicenseNumber(),MaskType.ID_CARD_NO),
                MaskCypherUtil.mask(accountName, MaskType.ID_CARD_NAME),
                MaskCypherUtil.mask(cardNo, MaskType.BANK_CARD_NO));

    }


    @Transactional(rollbackFor = Throwable.class)
    public BindCardAuthInitResultVO whiteListBindCard(BindCardAuthInitForm form, UserIdCode idCode) {

        if (StringUtils.isEmpty(form.getCardNo().replace(" ",""))) {
            throw ApplicationException.error(ApplicationExceptionCode.CARD_NO_EMPTY);
        }

        boolean hitWhiteList = false;
        if (!StringUtils.isEmpty(DepAccountWhiteList)) {
            List<UserIdCode> whiteIdCodeList = Arrays.stream(DepAccountWhiteList.split(","))
                    .map(Long::parseLong)
                    .map(UserIdCode::new)
                    .collect(Collectors.toList());
            hitWhiteList = whiteIdCodeList.contains(idCode);
        }

        if (!hitWhiteList) {
            throw ApplicationException.error(ApplicationExceptionCode.WHITE_LIST_NOT_HIT);
        }

        SignInfo signInfo = signService
                .getSignInfo(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));
        if (signInfo == null) {
            throw ApplicationException.error(ApplicationExceptionCode.SIGN_NOT_SUCCESS);
        }

        if (IdentityType.CERTIFIED_BUSINESS == signInfo.getIdentity()
                || IdentityType.CERTIFIED_INDIVIDUAL == signInfo.getIdentity()) {
            throw ApplicationException.error(ApplicationExceptionCode.CERTIFIED_NOT_SUPPORT);
        }

        //寻程 校验三要素
        userInfoService.checkBankIdCard(signInfo.personalDepAccountName(), form.getCardNo(), signInfo.personalDepAccountLicense().getLicenseNumber());

        DepositoryAccount result = depositoryAccountRepository
                .getByIdCodeLicense(idCode, convert(signInfo.personalDepAccountLicense()), DepositoryChannel.INTERNAL);
        if (result != null) {
            result.changeStatus(AccountStatus.NORMAL);
            depositoryAccountRepository.updateStatus(result);
        } else {
            DepositoryAccount depositoryAccount = new DepositoryAccount(null, idCode, DepositoryChannel.INTERNAL,
                    convert(signInfo.personalDepAccountLicense()), "", AccountStatus.NORMAL);
            result = depositoryAccountRepository.save(depositoryAccount);
        }


        if (result == null || result.getDepositoryAccountId() == null) {
            throw ApplicationException.error(ApplicationExceptionCode.DEP_ACCOUNT_OPEN_FAIL);
        }

        DepositoryBankCard bankCard = depositoryBankCardRepository.getByDepositoryAccountIdCardNo(idCode, result.getDepositoryAccountId(), form.getCardNo());

        if (bankCard != null) {
            bankCard.changeBindStatus(BindStatus.SUCCESS);
            depositoryBankCardRepository.updateByBankCardId(bankCard);
        } else {
            bankCard = new DepositoryBankCard(null, idCode, result.getDepositoryAccountId(),
                    BankCardType.PERSONAL, form.getCardNo(), "", "", BindStatus.SUCCESS, new BankCardExtra());
            depositoryBankCardRepository.save(bankCard);
        }

        return new BindCardAuthInitResultVO(bankCard.getStatus().getVal(), "", 0L);

    }



    public BindCardAuthInitResultVO bindInit(UserIdCode idCode, String ip, BindCardAuthInitForm form) {
        AccountType accountType = AccountType.ofInnerCode(form.getAccountBindType());
        SignInfo signInfo =
                signService.getSignInfo(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));

        if (signInfo == null || !signInfo.isSignedSuccess()) {
            throw ApplicationException.error(ApplicationExceptionCode.SIGN_NOT_SUCCESS);
        }

        String mobile;
        License license;
        String accountName;
        //个人账户：银行卡预留手机号  对公账户：用户登陆手机号
        if (AccountType.PERSONAL == accountType) {
            mobile = form.getMobileForBank();
            license = convert(signInfo.personalDepAccountLicense());
            accountName = signInfo.personalDepAccountName();
        } else {
            UserInfo userInfo = userInfoRepository
                    .getByIdCode(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));
            mobile = userInfo.getMobile();
            license = convert(signInfo.companyDepAccountLicense());
            accountName = signInfo.companyDepAccountName();
        }

        //开户
        DepositoryOpenAccountForm depositoryOpenAccountForm = new DepositoryOpenAccountForm(
                idCode, accountType, accountName, license,
                mobile, signInfo.legalName(), convert(signInfo.legalLicense()), ip);
        DepositoryAccount depositoryAccount =
                depositoryService.openDepositoryAccount(depositoryOpenAccountForm);

        //绑卡发起鉴权
        DepositoryBindCardForm depositoryBindCardForm = new DepositoryBindCardForm(depositoryAccount,
                license.getLicenseNumber(), BankCardType.ofInnerCode(form.getAccountBindType()),
                form.getBankName(), form.getSuperBankNo(), form.getCardNo(), mobile);
        AuthInitResult result = depositoryService.applyDepositoryBindCard(depositoryBindCardForm, idCode);

        return new BindCardAuthInitResultVO(result.getBindStatus().getVal(),
                result.getMsg(), result.getRemainSecond());


    }

    public BindCardAuthInitResultVO bindInitV2(UserIdCode idCode, String ip, BindCardAuthInitForm form) {
        AccountType accountType = AccountType.ofInnerCode(form.getAccountBindType());
        SignInfo signInfo =
                signService.getSignInfo(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));

        if (signInfo == null || !signInfo.isSignedSuccess()) {
            throw ApplicationException.error(ApplicationExceptionCode.SIGN_NOT_SUCCESS);
        }

        String mobile = form.getMobileForBank();
        License license;
        String accountName;
        //个人账户：银行卡预留手机号  对公账户：用户登陆手机号
        if (AccountType.PERSONAL == accountType) {
//            mobile = form.getMobileForBank();
            license = convert(signInfo.personalDepAccountLicense());
            accountName = signInfo.personalDepAccountName();
        } else {
//            UserInfo userInfo = userInfoRepository
//                    .getByIdCode(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));
//            mobile = userInfo.getMobile();
            license = convert(signInfo.companyDepAccountLicense());
            accountName = signInfo.companyDepAccountName();
        }

        //开户
        DepositoryOpenAccountForm depositoryOpenAccountForm = new DepositoryOpenAccountForm(
                idCode, accountType, accountName, license,
                mobile, signInfo.legalName(), convert(signInfo.legalLicense()), ip);
        DepositoryAccount depositoryAccount =
                depositoryService.openDepositoryAccount(depositoryOpenAccountForm);

        //绑卡发起鉴权
        DepositoryBindCardForm depositoryBindCardForm = new DepositoryBindCardForm(depositoryAccount,
                license.getLicenseNumber(), BankCardType.ofInnerCode(form.getAccountBindType()),
                form.getBankName(), form.getSuperBankNo(), form.getCardNo(), mobile);
        AuthInitResult result = depositoryService.applyDepositoryBindCard(depositoryBindCardForm, idCode);

        return new BindCardAuthInitResultVO(result.getBindStatus().getVal(),
                result.getMsg(), result.getRemainSecond());


    }

    public AuthPublicAccountInfoVO authPublicAccountInfo(UserIdCode userIdCode) {
        AuthPublicAccountInfoVO resultVO = new AuthPublicAccountInfoVO();


        // 获取银行卡信息
        DepositoryAccount account = depositoryAccountRepository.getByIdCodeStatusAuthing(userIdCode, DepositoryChannel.PING_AN);
        if (account == null) {
            throw new InterfaceException(InterfaceCode.VALID_ACCOUNT_QUERY_ERROR, userIdCode.getValue());
        }
        List<DepositoryBankCard> bankCardList = depositoryBankCardRepository
                .getByDepositoryAccountIdStatus(userIdCode, account.getDepositoryAccountId(), List.of(BindStatus.AUTHENTICATING));
        if (CollectionUtils.isEmpty(bankCardList)) {
            throw new InterfaceException(InterfaceCode.VALID_ACCOUNT_QUERY_ERROR, userIdCode.getValue());
        }
        DepositoryBankCard bankCard = bankCardList.stream()
                .filter(v -> v.getCardType() == BankCardType.PUBLIC).findFirst().orElse(null);
        if (bankCard == null) {
            throw new InterfaceException(InterfaceCode.VALID_ACCOUNT_QUERY_ERROR, userIdCode.getValue());
        }
        // 获取手机号
        String mobile = bankCard.getExtra().getReservedMobile();
        if (StringUtils.isEmpty(mobile)) {
            mobile = userInfoRepository.getByIdCode(new com.tengju.user.domain.model.user.UserIdCode(userIdCode.getValue())).getMobile();
        }

        // 获取过期时间
        LocalDateTime expireTime = bankCard.getExtra().getVerifyExpireTime();
        long resultSeconds = Duration.between(LocalDateTime.now(), expireTime).toSeconds();

        resultVO.formatSetCardNo(bankCard.getCardNo());
        resultVO.formatMobile(mobile);
        resultVO.setRemainSecond((resultSeconds > 0 ? resultSeconds : 0));

        // 按钮展示判断逻辑与提示信息
        if (expireTime.isBefore(LocalDateTime.now())) {
            resultVO.setButtonView(BindCardButtonView.APPLY_AGAIN.getVal());
            resultVO.setHintMsg("验证时间已超过48小时, 请重新申请验证");
            return resultVO;
        }
        boolean existCntKey = depositoryBankCardRepository.existCntKey(userIdCode);
        if (existCntKey) {
            Long bindCntTtl = depositoryBankCardRepository.bindCntTtl(userIdCode);
            Integer bindCardCnt = depositoryBankCardRepository.bindCardCnt(userIdCode);
            if (bindCardCnt >= maxBindCardCntForPingAnEveryday) {
                resultVO.setHintMsg("信息输入已超过5次, 请在24小时后重新申请 ");
            }
            LocalDateTime now = LocalDateTime.now();
            // 选择当前时间为基点, 进行时间比较
            if (now.plusSeconds(bindCntTtl).plusDays(1L).isAfter(now.plusSeconds(resultSeconds)) && bindCardCnt >= maxBindCardCntForPingAnEveryday) {
                resultVO.setButtonView(BindCardButtonView.APPLY_AGAIN.getVal());
            }
        }
        return resultVO;
    }

    @Transactional(rollbackFor = Exception.class)
    public AuthCheckResultVO authCheck(UserIdCode userIdCode, AuthCheckForm authCheckForm) {
        AuthCheckResultVO resultVO = new AuthCheckResultVO();
        String mobile;
        // redis 记录的绑卡次数
        int bindCardCnt = 1;
        DepositoryVerifyFrom verifyFrom;
        DepositoryVerifyResponse pingAnValidResult;
        DepositoryBankCard cardInfo = depositoryBankCardRepository.getByCardNo(userIdCode, authCheckForm.getCardNo());

        //小额鉴权 前置校验
        if (BankCardType.PUBLIC == cardInfo.getCardType()) {
            // 平安的 48 小时有效期, expireTime 是过期期间
            LocalDateTime expireTime = cardInfo.getExtra().getVerifyExpireTime();
            if (expireTime.isBefore(LocalDateTime.now()) || expireTime.equals(LocalDateTime.now())) {
                resultVO.setResult(false);
                resultVO.setHintMsg("验证时间已超过48小时, 请重新申请验证");
                resultVO.setButtonView(BindCardButtonView.APPLY_AGAIN.getVal());
                return resultVO;
            } else {
                Integer count = depositoryBankCardRepository.bindCardCnt(userIdCode);
                if (count == null) {
                    // 初始化bindCardCnt
                    depositoryBankCardRepository.bindCardCntInit(userIdCode, bindCardCnt, bindCardCntValidHours);
                } else {
                    bindCardCnt = count;
                    if (bindCardCnt > maxBindCardCntForPingAnEveryday) {
                        resultVO.setResult(false);
                        resultVO.setHintMsg("信息输入已超过5次, 请在24小时后重新申请 ");
                        if (expireTime.isBefore(LocalDateTime.now().plusDays(1L))) {
                            resultVO.setButtonView(BindCardButtonView.APPLY_AGAIN.getVal());
                        }
                        return resultVO;
                    }
                }
            }
        }

        // 获取账户信息
        DepositoryAccount depositoryAccount = depositoryAccountRepository.getByDepAccountId(cardInfo.getDepositoryAccountId());
        BankCardType cardType = BankCardType.ofInnerCode(authCheckForm.getAccountBindType());
        switch (cardType) {
            case PERSONAL:
                mobile = cardInfo.getExtra().getReservedMobile();
                verifyFrom = new DepositoryVerifyFrom(cardType, authCheckForm.getSms(),
                        depositoryAccount.getLicense(), authCheckForm.getCardNo(), mobile);
                break;
            case PUBLIC:
                double confirmAmount = Double.parseDouble(authCheckForm.getConfirmAmount());
                mobile = userInfoRepository.getByIdCode(new com.tengju.user.domain.model.user.UserIdCode(userIdCode.getValue()))
                        .getMobile();
                verifyFrom = new DepositoryVerifyFrom(cardType, authCheckForm.getSms(),
                        new Amount(BigDecimal.valueOf(confirmAmount)), depositoryAccount.getLicense(), authCheckForm.getCardNo(), mobile);
                break;
            default:
                throw new InterfaceException(InterfaceCode.BANK_CARD_TYPE_ILLEGAL, authCheckForm.getAccountBindType());
        }

        try {
            // 发起验证
            pingAnValidResult = paymentService.bindCardVerify(verifyFrom);
            boolean pingAnValid = pingAnValidResult.isVerifyResult();
            resultVO.setResult(pingAnValid);
            if (pingAnValid) {
                cardInfo.bindSuccess();
                depositoryAccount.changeStatus(AccountStatus.NORMAL);
                resultVO.setHintMsg("银行卡绑定成功");
            } else {
                if (BankCardType.PUBLIC == cardInfo.getCardType()) {
                    resultVO.setHintMsg(pingAnValidResult.getResultInfo() + ",验证剩余次数: " + (maxBindCardCntForPingAnEveryday - bindCardCnt));
                }
            }
            depositoryBankCardRepository.updateBindStatus(cardInfo);
            depositoryAccountRepository.updateStatus(depositoryAccount);
        } catch (Exception e) {
            log.error("发起鉴权失败，req{}", verifyFrom.toString(), e);
            throw new InterfaceException(InterfaceCode.PING_AN_VALID_BIND_CARD_ERROR);
        } finally {
            if (BankCardType.PUBLIC == cardInfo.getCardType()) {
                // 验证绑卡次数 +1
                depositoryBankCardRepository.bindCntIncrement(userIdCode);
            }
        }
        return resultVO;
    }

    public void bindFail(UserIdCode idCode) {
        //逻辑注销绑定中的账户
        DepositoryAccount depositoryAccount = depositoryAccountRepository.getByIdCodeStatusAuthing(idCode, DepositoryChannel.PING_AN);
        depositoryAccount.logicalCancel();
        depositoryAccountRepository.updateStatus(depositoryAccount);

        //绑卡置为失败
        List<DepositoryBankCard> bankCards = depositoryBankCardRepository
                .getByDepositoryAccountIdStatus(idCode, depositoryAccount.getDepositoryAccountId(),
                        List.of(BindStatus.AUTHENTICATING));

        if (CollectionUtils.isEmpty(bankCards)) {
            return;
        }

        if (bankCards.size() > 1) {
            throw ApplicationException.error(ApplicationExceptionCode.AUTHENTICATING_CARD_MORE_THAN_ONE);
        }

        DepositoryBankCard depositoryBankCard = bankCards.get(0);
        depositoryBankCard.changeBindStatus(BindStatus.FAIL);
        depositoryBankCardRepository.updateBindStatus(depositoryBankCard);

        //删除限制提交次数key
        depositoryBankCardRepository.delCardCnt(idCode);

    }

    public BindInfoVO bindInfo(UserIdCode userIdCode, QueryBindInfoForm form) {
        BankCardType bankCardType = BankCardType.ofInnerCode(form.getCardType());
        BindInfoVO bindInfoVO = new BindInfoVO();
        AbmDepositoryAggregatedInfo abmDepositoryInfo = null;
        if (form.getNeedSync()) {
            abmDepositoryInfo = paymentService.getAbmAggregatedInfoForDepository(userIdCode, DepositoryChannel.PING_AN);
            if (abmDepositoryInfo != null && abmDepositoryInfo.isValid()) {
                bankCardType = abmDepositoryInfo.getBankCard().getCardType();

            }
        }

        bindInfoVO.setCardType(form.getCardType());
        SignInfo signInfo = signService.getSignInfo(new com.tengju.user.domain.model.user.UserIdCode(userIdCode.getValue()));
        Assert.notNull(signInfo, "绑卡信息查询异常, idCode:" + userIdCode.getValue() + "银行账户类型: " + Optional.ofNullable(bankCardType).map(BankCardType::getDesc).orElse(""));
        // 绑卡返回的必要信息进行判空
        checkBindCardRequiredInfo(signInfo, bankCardType);

        License license;
        switch (bankCardType) {
            case PUBLIC:
                SelfCertification selfCertification = signInfo.getSelfCertification();
                bindInfoVO.setCompanyName(MaskCypherUtil.mask(selfCertification.getCompanyName(), MaskType.ACCOUNT_NAME));
                bindInfoVO.setCompanyNo(MaskCypherUtil.mask(selfCertification.getCompanyNo(), MaskType.SOCIALLY_UNIFIED_CODE));
                bindInfoVO.setIdCardName(MaskCypherUtil.mask(selfCertification.getIdCardName(), MaskType.ID_CARD_NAME));
                bindInfoVO.setIdCardNo(MaskCypherUtil.mask(selfCertification.getIdCardNo(), MaskType.ID_CARD_NO));
                license = new License(LicenseType.SOCIAL_CREDIT, selfCertification.getCompanyNo());
                break;
            case PERSONAL:
                bindInfoVO.setIdCardName(MaskCypherUtil.mask(signInfo.personalDepAccountName(), MaskType.ID_CARD_NAME));
                bindInfoVO.setIdCardNo(MaskCypherUtil.mask(signInfo.personalDepAccountLicense().getLicenseNumber(), MaskType.ID_CARD_NO));
                license = convert(signInfo.personalDepAccountLicense());
                break;
            default:
                throw new InterfaceException(InterfaceCode.BANK_CARD_TYPE_ILLEGAL, "request:" + form.getCardType());
        }
        //与abm证件号一致
        if (abmDepositoryInfo != null && abmDepositoryInfo.isValid() && abmDepositoryInfo.compareAccountLicense(license)) {
            bindInfoVO.setCardNo(abmDepositoryInfo.cardNo());
            bindInfoVO.setBankName(abmDepositoryInfo.bankName());
            bindInfoVO.setSuperBankNo(abmDepositoryInfo.superBankNo());
            bindInfoVO.setMobileForBank(abmDepositoryInfo.mobileForBank());
            bindInfoVO.setCardType(Optional.ofNullable(abmDepositoryInfo.cardType()).map(BankCardType::getInnerVal).orElse(null));
        }

        DepositoryAccount depositoryAccount = depositoryAccountRepository.getByIdCodeLicense(userIdCode, license, DepositoryChannel.PING_AN);
        bindInfoVO.setShowOpenAccountProtocol(depositoryAccount == null);
        return bindInfoVO;
    }

    public SupportBankVO supportBankList(Integer cardType) {
        SupportBankVO supportBankVO = new SupportBankVO(Lists.newArrayList());
        Set<String> hotSuperBankNumberSet;
        List<BankInfo> supportBankList = paymentService.getSupportBankList(BankCardType.ofInnerCode(cardType));
        if (CollectionUtils.isEmpty(supportBankList)) {
            return supportBankVO;
        }
        // apollo 获取配置的热门银行的超级网银号
        Map<String, String> superNoAndImgUrlMaps = JsonUtil.toMap(hotSuperBankNumberImgUrlMapJson);
        if (CollectionUtils.isEmpty(superNoAndImgUrlMaps)) {
            hotSuperBankNumberSet = new HashSet<>();
        } else {
            hotSuperBankNumberSet = superNoAndImgUrlMaps.keySet();
        }
        List<BankInfo> hotBankList = Lists.newArrayList();
        // 获取排序后的所有银行 A : [A_bank1,A_bank2]
        TreeMap<String, List<BankInfo>> allBanks = supportBankList.stream().filter(Objects::nonNull).peek(v -> {
            if (hotSuperBankNumberSet.contains(v.getSuperBankCode().strip())) {
                hotBankList.add(v);
            }
        }).collect(Collectors.groupingBy(v -> ChineseCharactersUtil
                .getFirstUpperCharByChinese(v.getBankName()), TreeMap::new, Collectors.toList()));
        SupportBankInfo hotBankForm = new SupportBankInfo("热门", hotBankList);
        List<SupportBankInfo> bankList = supportBankVO.getBankList();
        bankList.add(hotBankForm);
        for (String key : allBanks.keySet()) {
            bankList.add(new SupportBankInfo(key, allBanks.get(key)));
        }
        return supportBankVO;
    }

    public BoundCardVO boundCardList(UserIdCode idCode) {
        BoundCardVO resultVO = new BoundCardVO(Lists.newArrayList());
        Map<String, String> superNoAndImgUrlMaps = JsonUtil.toMap(hotSuperBankNumberImgUrlMapJson);
        DepositoryAccount depositoryAccount = depositoryAccountRepository.getByIdCodeStatusNormal(idCode, DepositoryChannel.PING_AN);
        if (depositoryAccount == null || CollectionUtils.isEmpty(superNoAndImgUrlMaps)) {
            return resultVO;
        }
        List<DepositoryBankCard> depositoryBankCards = depositoryBankCardRepository
                .getByDepositoryAccountIdStatus(depositoryAccount.getIdCode(), depositoryAccount.getDepositoryAccountId(), List.of(BindStatus.SUCCESS));
        if (CollectionUtils.isEmpty(depositoryBankCards)) {
            return resultVO;
        }
        return new BoundCardVO(depositoryBankCards.stream().filter(Objects::nonNull).map(v -> new BankInfo(
                v.getBankName(), MaskCypherUtil.mask(v.getCardNo(), MaskType.BANK_CARD_NO),
                Optional.ofNullable(superNoAndImgUrlMaps.get(v.getSuperBankNo())).orElse(superNoAndImgUrlMaps.get("default"))
        )).collect(Collectors.toList()));
    }


    private License convert(com.tengju.user.domain.model.sign.License license) {
        if (license == null) {
            return null;
        }
        return new License(LicenseType.fromVal(license.getLicenseType().getVal()),
                license.getLicenseNumber());
    }

    /**
     * 绑卡返回的必要信息进行判空
     *
     * @param signInfo 签约信息
     * @param cardType 银行卡账户类型
     */
    private void checkBindCardRequiredInfo(SignInfo signInfo, BankCardType cardType) {
        if (cardType == null) {
            throw new InterfaceException(InterfaceCode.DEP_CARD_TYPE_EMPTY);
        }
        switch (cardType) {
            case PUBLIC:
                SelfCertification selfCertification = signInfo.getSelfCertification();
                Assert.notNull(selfCertification, "未找到签约信息");
                Assert.notNull(selfCertification.getCompanyName(), "对公账户绑卡信息查询异常, 企业名称不能为空");
                Assert.notNull(selfCertification.getCompanyNo(), "对公账户绑卡信息查询异常, 社会信用代码不能为空");
                Assert.notNull(selfCertification.getIdCardName(), "对公账户绑卡信息查询异常, 法人姓名不能为空");
                Assert.notNull(selfCertification.getIdCardNo(), "对公账户绑卡信息查询异常, 法人身份证号不能为空");
                break;
            case PERSONAL:
                Assert.notNull(signInfo.personalDepAccountName(), "个人账户绑卡信息查询异常, 姓名不能为空");
                Assert.notNull(signInfo.personalDepAccountLicense().getLicenseNumber(), "个人账户绑卡信息查询异常, 身份证号不能为空");
                break;
            default:
                throw new InterfaceException(InterfaceCode.BANK_CARD_TYPE_ILLEGAL, "request:" + cardType);
        }
    }

}
